#ifndef AABB_H_INCLUDED
#define AABB_H_INCLUDED

namespace engine {

	namespace scene {
		
		///Axis-aligned bounding box	
		class AABB {
			private:
				slVec3 m_Min;
				slVec3 m_Max;
				
			public:
				AABB(const slVec3& min, const slVec3& max) {
					m_Min = min;
					m_Max = max;
				}
				
				AABB(const slVec3& centre, const float radius) {
					m_Min.m_X = centre.m_X - radius;
					m_Min.m_Y = centre.m_Y - radius;
					m_Min.m_Z = centre.m_Z - radius;

					m_Max.m_X = centre.m_X + radius;
					m_Max.m_Y = centre.m_Y + radius;
					m_Max.m_Z = centre.m_Z + radius;
				}
				
				AABB() {
					
				}
				
				slVec3 getCentre() {
					return slVec3( 	m_Min.m_X + (m_Max.m_X - m_Min.m_X)/2,
									m_Min.m_Y + (m_Max.m_Y - m_Min.m_Y)/2,
									m_Min.m_Z + (m_Max.m_Z - m_Min.m_Z)/2 );							
				}
				
				///Builds the AABB from a list of vertices
				void resizeFromVertexList(const vector<slVec3>& vertices) {
					for (vector<slVec3>::const_iterator it = vertices.begin();
							it != vertices.end(); ++it) {
					
						//Set these to stupid values then we know we have fit to 
						//the right size
						m_Min = slVec3(100000, 100000, 100000);
						m_Max = slVec3(-100000, -100000, -100000);
						
						if ((*it).m_X < m_Min.m_X) m_Min.m_X = (*it).m_X;
						if ((*it).m_Y < m_Min.m_Y) m_Min.m_Y = (*it).m_Y;
						if ((*it).m_Z < m_Min.m_Z) m_Min.m_Z = (*it).m_Z;
						
						if ((*it).m_X > m_Max.m_X) m_Max.m_X = (*it).m_X;
						if ((*it).m_Y > m_Max.m_Y) m_Max.m_Y = (*it).m_Y;
						if ((*it).m_Z > m_Max.m_Z) m_Max.m_Z = (*it).m_Z;
					}
				}
				
				const slVec3& getMin() const { return m_Min; }
				const slVec3& getMax() const { return m_Max; }
				
				void setMinX(float x) { m_Min.m_X = x; }
				void setMinY(float y) { m_Min.m_Y = y; }
				void setMinZ(float z) { m_Min.m_Z = z; }
				
				float getMinX() const { return m_Min.m_X; }
				float getMinY() const { return m_Min.m_Y; }
				float getMinZ() const { return m_Min.m_Z; }
				
				void setMaxX(float x) { m_Max.m_X = x; }
				void setMaxY(float y) { m_Max.m_Y = y; }
				void setMaxZ(float z) { m_Max.m_Z = z; }

				float getMaxX() const { return m_Max.m_X; }
				float getMaxY() const { return m_Max.m_Y; }
				float getMaxZ() const { return m_Max.m_Z; }
								
				float getMaxWidth() {
					float min = getMinX();
					float max = getMaxX();
					
					if (getMinY() < min) min = getMinY();
					if (getMinZ() < min) min = getMinZ();
					
					if (getMaxY() > max) max = getMaxY();
					if (getMaxZ() > max) max = getMaxZ();
					
					return max-min;
				}
				
				bool pointInBox(const slVec3& vec) {
					return ((vec.m_X <= m_Max.m_X && vec.m_X >= m_Min.m_X ) &&
					(vec.m_Y <= m_Max.m_Y && vec.m_Y >= m_Min.m_Y ) &&
					(vec.m_Z <= m_Max.m_Z && vec.m_Z >= m_Min.m_Z ) );
				}
				
				bool doesTriangleFit(const slVec3& v1, const slVec3& v2, const slVec3& v3) {
					
					return (pointInBox(v1) && pointInBox(v2) && pointInBox(v3));
					
				}
		};
	}
}

#endif // AABB_H_INCLUDED
